import {
  getControlsByView,
  IModal,
  IViewLayoutPanelController,
  ViewController,
} from '@ibiz-template/runtime';
import { useNamespace, useViewController } from '@ibiz-template/vue3-util';
import { IAppView } from '@ibiz/model-core';
import {
  defineComponent,
  h,
  PropType,
  resolveComponent,
  onActivated,
  onDeactivated,
  VNode,
} from 'vue';
import './view.scss';

export const View = defineComponent({
  name: 'IBizView',
  props: {
    context: Object as PropType<IContext>,
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    modelData: { type: Object as PropType<IAppView>, required: true },
    modal: { type: Object as PropType<IModal> },
    state: { type: Object as PropType<IData> },
  },
  setup() {
    const ns = useNamespace('view');
    const c = useViewController((...args) => new ViewController(...args));
    // 视图部件模型在viewlayoutPanel里面。
    const controls = getControlsByView(c.model);
    const { viewType, sysCss, codeName } = c.model;
    const typeClass = viewType!.toLowerCase();
    const sysCssName = sysCss?.cssName;
    const viewClassNames = [
      ns.b(),
      true && ns.b(typeClass),
      true && ns.m(codeName),
      true && sysCssName,
    ];

    const onLayoutPanelCreated = (
      controller: IViewLayoutPanelController,
    ): void => {
      c.setLayoutPanel(controller as IViewLayoutPanelController);
    };

    onActivated(() => c.onActivated());

    onDeactivated(() => c.onDeactivated());

    return { c, controls, viewClassNames, onLayoutPanelCreated };
  },
  render() {
    let layoutPanel = null;
    if (this.c.state.isCreated) {
      // 绘制部件插槽，外部插槽优先
      const slots: IData = {
        ...this.$slots,
      };
      if (this.controls?.length) {
        this.controls.forEach(ctrl => {
          const slotKey = ctrl.name! || ctrl.id!;
          const ctrlProps = {
            context: this.c.context,
            params: this.c.params,
          };
          if (this.c.slotProps[slotKey]) {
            Object.assign(ctrlProps, this.c.slotProps[slotKey]);
          }
          // 已经有插槽的不用自己绘制了。
          const outCtrlSlot = slots[slotKey];
          if (outCtrlSlot) {
            slots[slotKey] = (): VNode => {
              return outCtrlSlot(ctrlProps);
            };
            return;
          }
          const provider = this.c.providers[slotKey];
          if (provider) {
            slots[slotKey] = (): VNode => {
              const comp = resolveComponent(provider.component) as string;
              return h(comp, {
                modelData: ctrl,
                ...ctrlProps,
              });
            };
          }
        });
      }

      if (this.c.engines.length === 0) {
        layoutPanel = (
          <span style={'color:red;'}>
            视图类型{this.modelData.viewType}暂未支持
          </span>
        );
      } else {
        // 绘制视图布局面板
        const viewLayoutPanel = this.c.model.viewLayoutPanel!;
        const provider = this.c.providers[viewLayoutPanel.name!];
        layoutPanel = h(
          resolveComponent(provider.component) as string,
          {
            modelData: viewLayoutPanel,
            context: this.c.context,
            params: this.c.params,
            onControllerAppear: this.onLayoutPanelCreated,
          },
          slots,
        );
      }
    }

    return (
      <div class={this.viewClassNames} v-loading={this.c.state.isLoading}>
        {layoutPanel}
      </div>
    );
  },
});
